home *** CD-ROM | disk | FTP | other *** search
- /*
- * Terminal emulator for use with Macintosh and Stevie 3.69.
- * Aztec C 3.6c.
- * Earle R. Horton 11/23/89.
- */
- #include <windows.h>
- #include <events.h>
- #include <menus.h>
- #include <fonts.h>
- #include <dialogs.h>
- #include <quickdraw.h>
- #include <osutils.h>
- #include <desk.h>
- #include <resources.h>
- #include <memory.h>
- #include <files.h>
- #include <SegLoad.h>
- #undef normal
- #include "stevie.h"
-
- #define leftoffset 4
- #define ORIG_ROWS 24
- #define ORIG_COLUMNS 80
-
- short cwd; /* Current working directory. */
- char wdname[256]; /* Working directory or volume name. */
- static char progname[32]; /* Program name for argv[0]. */
- static char pname[32]; /* Program name in Pascal. */
- struct Rect dragRect, pRect;
- struct WindowRecord wRecord;
- struct GrafPort *myWindow, *whichWindow;
- struct EventRecord myEvent;
- RgnHandle updateRgn;
- Boolean dead = false;
-
- short x=0, y=0;
- static short escflg = 0, ex, ey, savex, savey;
-
- main()
- {
- AppFile fParm;
- short message, count, index;
- Handle apparams;
- short refnum;
- char **Files;
- extern int Rows,Columns;
-
- long stackframeend;
-
- char *lmalloc();
-
- /*
- * Here we get the current value of the stack pointer, and set
- * the end of the application heap zone to somewhat less than this.
- * Then, we remove 128k of memory from the system pool and put it
- * in our pool. This helps to prevent frequent calls to malloc()
- * from fragmenting the heap. For this to work properly, please
- * use an implementation where free() does NOT call DisposPtr().
- *
- * These numbers, with a 256k MultiFinder partition, give approximately
- * the following amounts of storage:
- * 25k Stack
- * 55k System use (free and relocatable blocks)
- * 128k For use by malloc()
- * 55k CODE
- */
- SetApplLimit( (long)(&stackframeend) - 20000L );
- MaxApplZone(); /* We want it. */
- free(lmalloc(131072L)); /* Prime the pump. */
-
- /*
- * Are there any Files launched from the Finder? If so, build
- * a standard C program argument list.
- */
- CountAppFiles(&message, &count);
- GetAppParms(&pname,&refnum,&apparams);
- strcpy(progname,pname);
- p2cstr(progname);
-
- Files = (char **)malloc((count+1)*sizeof(char *));
- Files[0] = progname;
- /*
- * Get default volume in case we were invoked with no files.
- */
- GetVol(wdname,&cwd);
- /* Process the files */
- for(index=1;index<=count;index++) {
- GetAppFiles(index, &fParm);
- ClrAppFiles(index);
- Files[index]=(char *)malloc(fParm.fName.length+1);
- p2cstr(&fParm.fName);
- strcpy(Files[index],&fParm.fName);
- /*
- * Use as the default directory that directory which holds the last
- * file we were invoked with. Problem if we are invoked with files
- * in more than one directory and caller does not use pathnames.
- */
- wdname[0] = '\0';
- cwd = fParm.vRefNum;
- }
- SetVol(wdname,cwd);
-
- InitGraf(&qd.thePort);
- InitWindows();
- InitFonts();
- setupmenu();
- InitDialogs(0L);
- InitCursor();
-
- SetRect(&dragRect, 4, 24,
- qd.screenBits.bounds.right-4,
- qd.screenBits.bounds.bottom-4);
-
- pRect.top = 40;
- pRect.left = 5;
- pRect.bottom = ORIG_ROWS*12;
- pRect.right = (ORIG_COLUMNS+1)*6;
- myWindow = NewWindow(
- &wRecord,&pRect,pname,true,0,(WindowPtr)-1L,0,0L);
- P(P_CO) = Columns = ORIG_COLUMNS;
- P(P_LI) = Rows = ORIG_ROWS;
- windresize();
- SelectWindow(myWindow);
- ShowWindow(myWindow);
- SetPort(myWindow);
-
- TextFont(4); /* monaco */
- TextSize(9);
- TextMode(srcCopy);
-
- updateRgn = NewRgn();
-
- xmain(count+1,Files);
-
- }
- /*
- * This piece of trash serves to allow our window to come up in front
- * under MultiFinder. If we have the canBackGround bit set in our
- * 'SIZE' resource, then we come up in the background when MultiFinder
- * is active. Since we are an interactive application, we want to
- * come up in the foreground, with user option to swap us back. Tossing
- * a few events (yuch) is the recommended way to get brought forward.
- * This code also leaves any startup message on the screen for about
- * a half second before we get to work.
- */
- void windinit()
- {
- long time;
- time = TickCount() + 30L;
- while(time > TickCount()){
- (void)GetNextEvent(everyEvent, &myEvent);
- }
- }
- /*
- * Resize the window according to the globals Rows and Columns. If window
- * contents ever get buffered, this would be the time to reallocate the
- * window contents buffer.
- */
- windresize()
- {
- SizeWindow(myWindow,(leftoffset*2)+(Columns*6),Rows*12,false);
- }
- int inchar()
- {
- short i = 0,j = 0;
- short code;
- static long lastblink = 0L;
- static Boolean wactive = true;
- Boolean on;
- long l;
-
- flushbuf();
- SetPort(myWindow);
- PenMode(patXor);
- PenSize(7,11);
- MoveTo(leftoffset - 1 + x * 6,y*12);
- /*
- * Blink the cursor on.
- */
- if(wactive){
- Line(0,0);
- }
- on = true;
- for(; i == 0 ;){
- do{
- SystemTask();
- /*
- * Blink the cursor every GetCaretTime() ticks while waiting for input.
- */
- if(wactive){
- if(TickCount() > (lastblink + GetCaretTime())){
- Line(0,0);
- lastblink = TickCount();
- on = !on;
- }
- }
- }while (!GetNextEvent(everyEvent, &myEvent));
- /*
- * Blink the cursor off while servicing events.
- */
- if(wactive){
- if(on){
- Line(0,0);
- lastblink = TickCount();
- on = false;
- }
- }
- switch(myEvent.what) {
- case mouseDown:
- code = FindWindow(myEvent.where, &whichWindow);
- switch (code) {
- case inMenuBar:
- docommand(MenuSelect(myEvent.where));
- break;
- case inSysWindow:
- SystemClick(&myEvent, whichWindow);
- break;
- case inDrag:
- DragWindow(whichWindow, myEvent.where, &dragRect);
- break;
- case inGrow:
- case inContent:
- if (whichWindow != FrontWindow())
- SelectWindow(whichWindow);
- else {
- }
- break;
- }
- break;
- /*
- * The next piece of code attempts to get a meaningful ASCII character
- * out of the event record. Some translation is done so the program
- * doesn't look totally clueless with respect to basic stuff like
- * arrow keys and Enter, but very little else is done except to
- * map command to control.
- */
- case keyDown:
- case autoKey:
- if (myWindow == FrontWindow()) {
- i = myEvent.message & 0xff;
- if ((myEvent.modifiers & cmdKey) && (l = MenuKey(i))) {
- docommand(l);
- i = 0;
- }
- else if (myEvent.modifiers & cmdKey) {
- if ( i == '6'){
- i = CTRL('^');
- }
- else if ( i == '/' ){ /* Actually '?'. */
- i = K_HELP;
- }else{
- i &= 0x1f;
- }
- }
- else if (State == NORMAL){
- if ( (i & 0xFF) < 0x20 ){
- switch(i){
- case CTRL('C'):
- i = CTRL('J');
- break;
- case CTRL('^'):
- i = K_UARROW;
- break;
- case CTRL('_'):
- i = K_DARROW;
- break;
- case CTRL(']'):
- i = K_RARROW;
- break;
- case CTRL('\\'):
- i = K_LARROW;
- break;
- }
- }
- }
- }
- break;
-
- case activateEvt:
- /*
- * If we get an activate event, then blink the cursor on.
- */
- if(myEvent.message == (long)myWindow){
- if (myEvent.modifiers & activeFlag) {
- wactive = true;
- }else{
- wactive = false;
- if(on){
- Line(0,0);
- lastblink = TickCount();
- on = false;
- }
- }
- }
- break;
-
- case updateEvt:
- if(myEvent.message == (long)myWindow){
- SetPort(myWindow);
- BeginUpdate(myWindow);
-
- redrawit();
-
- EndUpdate(myWindow);
- }
- break;
- }
- }
- return i;
- }
-
- /*
- * Redraw the window contents. Currently has the host program do this.
- * A better alternative would be to maintain a character buffer to store
- * the window contents and take care of this here.
- */
- redrawit()
- {
- int savex,savey;
- if(!dead){
- savex = x;
- savey = y;
- screenclear();
- updatescreen();
- flushbuf();
- x = savex;
- y = savey;
- MoveTo(leftoffset - 1 + x * 6,y*12);
- }
- }
- #undef exit
- void windexit(status)
- int status;
- {
- if(status){
- ParamText(pname,pname,pname,pname);
- Alert(128,nil);
- }
- exit(status);
- }
- /*
- * Substitute for [f]printf in the Mac environment.
- * A more sophisticated approach might be to intercept write calls,
- * but each compiler probably implements these differently.
- */
- #undef fprintf
- #undef printf
- myfprintf(a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac)
- FILE *a1;
- char *a2;
- long a3,a4,a5,a6,a7,a8,a9,aa,ab,ac;
- {
- char sbuf[2048];
- char *s,c;
-
- if( a1 == stderr || a1 == stdout || a1 == stdin ){
- sprintf(sbuf,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac);
- s = &sbuf[0];
- for(;(c = *s++);){
- switch (c){
- case NL:
- case CR:
- outchar(0x0a);
- outchar(0x0d);
- break;
- default:
- outchar(c);
- break;
- }
- }
- flushbuf();
- }else{
- fprintf(a1,a2,a3,a4,a5,a6,a7,a8,a9,aa,ab,ac);
- }
- }
-
- /*
- * Characters are generally buffered, which means we can use StdText()
- * to draw a bunch of them. This is faster than repeated calls to
- * DrawChar().
- */
- #define BSIZE 128
- static char outbuf[BSIZE];
- static int bpos = 0;
- void
- flushbuf()
- {
- if (bpos != 0){
- MoveTo((x*6)+leftoffset, (y*12)+9);
- StdText((short)bpos,outbuf,0x00010001,0x00010001);
- x += bpos;
- bpos = 0;
- }
- }
-
- /*
- * Entry point to draw characters on the screen. Buffer them up until
- * a control character appears or the buffer becomes full.
- */
- void outchar(c)
- register unsigned char c;
- {
- if(c < 0x20 || escflg != 0) {
- flushbuf();
- scrput(c);
- }
- else{
- outbuf[bpos++] = c;
- if (bpos >= BSIZE)
- flushbuf();
- }
- }
-
- void outstr(s)
- register char *s;
- {
- while(*s){
- outchar(*s++);
- }
- }
-
- void beep()
- {
- scrput('\007');
- }
-
- void remove(file)
- char *file;
- {
- char fsfile[256];
- strcpy(fsfile,file);
- c2pstr(fsfile);
- FSDelete(fsfile,cwd);
- }
-
- void rename(of,nf)
- char *of,*nf;
- {
- char fsof[256],fsnf[256];
- strcpy(fsof,of);
- strcpy(fsnf,nf);
- c2pstr(fsof);
- c2pstr(fsnf);
- SetVol(wdname,cwd);
- Rename(fsof,cwd,fsnf);
- }
-
- csave()
- {
- savex = x;
- savey = y;
- }
-
- crestore()
- {
- x = savex;
- y = savey;
- }
-
- static
- del_lin(lin)
- {
- struct Rect rect;
-
- rect.left = 0;
- rect.right = ((GrafPtr)myWindow)->portRect.right;
- rect.top = lin * 12;
- rect.bottom = ((GrafPtr)myWindow)->portRect.bottom;
- ScrollRect(&rect, 0, -12, updateRgn);
- }
-
- static
- ins_lin(lin)
- {
- struct Rect rect;
-
- rect.left = 0;
- rect.right = ((GrafPtr)myWindow)->portRect.right;
- rect.top = lin * 12;
- rect.bottom = ((GrafPtr)myWindow)->portRect.bottom;
- ScrollRect(&rect, 0, 12, updateRgn);
- }
-
- static
- clr_eol()
- {
- struct Rect rect;
-
- rect.left = leftoffset + x * 6;
- rect.top = y * 12;
- rect.right = ((GrafPtr)myWindow)->portRect.right;
- rect.bottom = rect.top + 13;
- EraseRect(&rect);
- }
-
- scrput(c)
- register unsigned char c;
- {
- register short i;
- struct Rect r;
- GrafPtr tmpport;
-
- GetPort(&tmpport);
- SetPort(myWindow);
-
- switch(escflg) {
- case 0:
- switch(c) {
- case 0x1b:
- escflg = 1;
- return;
- case 0x07:
- SysBeep(1);
- break;
- case 0x08:
- if (x)
- x--;
- break;
- case 0x09:
- c = ((x + 4) & ~3) - x;
- while(c--)
- scrput(' ');
- return;
- case 0x0a:
- if( y < (myWindow->portRect.bottom/12) - 1 )
- y++;
- else del_lin(0);
- break;
- case 0x0d:
- x = 0;
- break;
- default:
- if (c >= 0x20){
- outbuf[bpos++] = c;
- if (bpos >= BSIZE)
- flushbuf();
- }
- break;
- }
- break;
- case 1:
- switch(c) {
- case 'R':
- del_lin(y);
- x = 0;
- break;
- case 'E':
- ins_lin(y);
- x = 0;
- break;
- case 'T':
- clr_eol();
- break;
- case '=':
- escflg = 2;
- return;
- case ';':
- EraseRect(&qd.thePort->portRect);
- x = y = 0;
- break;
- case '7':
- csave();
- break;
- case '8':
- crestore();
- break;
- default:
- break;
- }
- escflg = 0;
- break;
- case 2:
- ey = c - ' ';
- escflg++;
- break;
- case 3:
- ex = c - ' ';
- escflg = 0;
- if (ey >= 0 && ex >= 0) {
- y = ey;
- x = ex;
- }
- break;
- }
-
- SetPort(tmpport);
- }
-
- void windgoto(r,c)
- register int r,c;
- {
- char cbuf[20];
- sprintf(cbuf,"\033=%c%c",r + ' ',c + ' ');
- outstr(cbuf);
- }
-
-
- #define appleMenu 255
- #define fileMenu 256
- #define editMenu 257
-
- #define NMENUS 3
-
- MenuHandle myMenus[NMENUS];
-
- setupmenu()
- {
- short i;
- char about[256];
-
- InitMenus();
- myMenus[0] = GetMenu(appleMenu);
- GetItem(myMenus[0],1,about);
- p2cstr(about);
- strcat(about,progname);
- strcat(about,"…");
- c2pstr(about);
- SetItem(myMenus[0],1,about);
- AddResMenu(myMenus[0], 'DRVR');
- myMenus[1] = GetMenu(fileMenu);
- myMenus[2] = GetMenu(editMenu);
- for (i=0;i<NMENUS;i++)
- InsertMenu(myMenus[i], 0);
- DrawMenuBar();
- }
-
- docommand(mResult)
- long mResult;
- {
- register short i;
- short theItem, theMenu;
- char name[40];
- int savex,savey;
-
- theMenu = mResult >> 16;
- theItem = mResult;
- switch(theMenu) {
- case appleMenu:
- if (theItem == 1) {
- savex = x;savey = y;
- help();
- redrawit();
- x = savex;y = savey;
- MoveTo(leftoffset - 1 + x * 6,y*12);
- }
- else{
- GetItem(myMenus[0], theItem, name);
- OpenDeskAcc(name);
- }
- break;
- case fileMenu:
- windexit();
- break;
- case editMenu:
- (void)SystemEdit(theItem - 1);
- break;
- }
- HiliteMenu(0);
- }
-
- #undef fopen
- FILE *
- fopenb(fname, mode)
- char *fname;
- char *mode;
- {
- char pname[256];
- FInfo info;
- if ( mode[0] == 'w' ) {
- strcpy(pname,fname);
- c2pstr(pname);
- if(GetFInfo(pname,cwd,&info) != noErr){
- Create(pname,cwd,'STvi','TEXT');
- }
- }
- SetVol(wdname,cwd);
- return fopen(fname, mode);
- }
-
- void
- doshell()
- {
- }
- system()
- {
- }
- /*
- * delay() is called to flash to matching braces when showmatch is on
- * in Stevie. This version turns on the cursor, pauses for a bit, then
- * turns off the cursor.
- */
- void
- delay()
- {
- long dtime = 6L;
- SetPort(myWindow);
- PenMode(patXor);
- PenSize(7,11);
- MoveTo(leftoffset - 1 + x * 6,y*12);
- Line(0,0);
- Delay(dtime,&dtime);
- Line(0,0);
- }
- sleep()
- {
- }
- /*
- * "Environment variables" are stored as named resources of type 'STR '.
- */
- char *getenv(str)
- char str[];
- {
- char pname[256];
- static char result[256];
- char **envstr;
- strcpy(pname,str);
- c2pstr(pname);
- if((envstr = (char **)GetNamedResource('STR ',pname)) != nil){
- HLock(envstr);
- p2cstr(*envstr);
- strcpy(result,*envstr);
- ReleaseResource(envstr);
- return result;
- }
- else return (char *)0L;
- }
-